package com.qst.medical.config.security;

import com.qst.medical.filter.JwtFilter;
import com.qst.medical.handler.security.CustomizeAuthenticationEntryPoint;
import com.qst.medical.handler.security.MyAccessDeniedHandler;
import com.qst.medical.handler.security.MyAuthenticationFailHandler;
import com.qst.medical.handler.security.MyAuthenticationSuccessHandler;
import com.qst.medical.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@Configuration // 标识Spring配置类
@EnableWebSecurity // 启用Web安全配置
@EnableGlobalMethodSecurity(jsr250Enabled = true) // 启用方法级安全配置，支持RolesAllowed等注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { // 继承WebSecurityConfigurerAdapter，提供安全配置

    @Autowired // 自动注入
    private UserDetailsServiceImpl userDetailsService; // 自定义登录业务类

    @Autowired
    private MyAuthenticationFailHandler authenticationFailHandler; // 登录失败处理

    @Autowired
    private MyAuthenticationSuccessHandler authenticationSuccessHandler; //登录成功处理

    @Autowired
    private CustomizeAuthenticationEntryPoint authenticationEntryPoint; //未登录或登录失效处理

    @Autowired
    private MyAccessDeniedHandler accessDeniedHandler; // 无权限处理器

    @Autowired
    private JwtFilter jwtFilter; // JWT（Java Web Token）校验

    @Bean // 注册Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder(); // 配置密码编码器为BCrypt，用于加密用户密码，提供安全的密码存储
    }

    @Override // 重写父类方法
    protected void configure(HttpSecurity http) throws Exception { // throws Exception 抛出异常
        http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); // 添加JWT过滤器,在用户名密码过滤器之前添加,确保JWT过滤器优先执行
        http.formLogin() // 表单登录配置
                .loginProcessingUrl("/api/login") // 指定登录处理URL
                .successHandler(authenticationSuccessHandler) // 登录成功处理
                .failureHandler(authenticationFailHandler) // 登录失败处理
                .and() // 作用：结束当前配置块并返回到上一级配置上下文
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint) // 未登录或登录失效处理
                .accessDeniedHandler(accessDeniedHandler) // 无权限处理器
                .and().authorizeRequests() // 授权请求配置
                .antMatchers("/api/login","/login","/v2/api-docs", "/swagger-resources/configuration/ui",
                        "/swagger-resources", "/swagger-resources/configuration/security",
                        "/swagger-ui.html", "/webjars/**", "api/login", "//api/login", "/static.image/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .cors()
                .configurationSource(configurationSource())
                .and()
                .csrf().disable();
    }

    /**
     * 解决前后端使用security跨域问题
     * @return
     */
    CorsConfigurationSource configurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        //corsConfiguration.setAllowCredentials(true);//前后端分离项目需要携带cookie时，需要此句，但加上之后origin里就不能�?"*"
        corsConfiguration.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",corsConfiguration);
        return source;
    }


}